#!/usr/bin/env bash

include "objectv5.sh"
include "test.sh"

ObjectV5::DefineClass Waiting "
    --string=task_pid,0
    --string=task_status,0
"

trap 'exit' SIGTERM
function Waiting::_SleepLoop()
{
    while true; do
        sleep 10000000
    done
}

Waiting_SleepLoop_task=""
function Waiting::_Kill()
{
    local pid="$1"
    for subpid in $(ps -ef | awk '$3=='$pid'{print $2}'); do
        Waiting::_Kill $subpid
    done
    kill -SIGTERM "$pid" 2>/dev/null
}

function Waiting::RunTask()
{
    local this="$1"; shift

    local taskpid=""
    if [ "$*" != "" ]; then
        eval "$@" &
        taskpid="$!"
        Waiting::task_pid "$this" "$taskpid"
        debuglog "cmd: $*, pid: $taskpid"
    fi

    Waiting::_SleepLoop &
    Waiting_SleepLoop_task="$!"
    trap 'Waiting::_Kill $Waiting_SleepLoop_task' SIGINT

    debuglog "waiting: $taskpid $Waiting_SleepLoop_task"
    wait -n $taskpid "$Waiting_SleepLoop_task"

    local retval="$?"
    if ! IsProcExist "$Waiting_SleepLoop_task"; then
        debuglog "SIGINT"
        return 1
    fi

    debuglog "Task"
    Waiting::_Kill "$Waiting_SleepLoop_task"
    Waiting::_Kill "$taskpid"
    Waiting_SleepLoop_task=""
    trap - SIGINT

    Waiting::task_status "$this" "$retval"
    return 0
}

function Waiting::KillTask()
{
    local this="$1"; shift
    local taskpid="$(Waiting::task_pid "$this")"
    if [ "$taskpid" != "" ] && IsProcExist "$taskpid"; then
        debuglog "kill -SIGTERM $taskpid"
        kill -SIGTERM "$taskpid"
    fi
}

function Waiting::GetTaskStatus()
{
    local this="$1"; shift
    return "$(Waiting::task_status "$this")"
}

function Waiting::Test1()
{
    Waiting waiting
    (sleep 0.5; kill -SIGINT $$) &
    if Waiting::RunTask waiting "sleep 1; true"; then
        test::failed "should return false"
    else
        test::succed
    fi

    if Waiting::RunTask waiting "true"; then
        test::succed
    else
        test::failed "should return true"
    fi

    local tempfile="$(mktemp "/tmp/Waiting.XXXXXXXX")"
    (sleep 0.5; kill -SIGINT $$) &
    Waiting::RunTask waiting "sleep 1; rm -f $tempfile; echo removed"
    test::should_return_true [ -e "$tempfile" ]
    Waiting::KillTask waiting
    sleep 1
    test::should_return_true [ -e "$tempfile" ]
    rm -f $tempfile

    Waiting::RunTask waiting "(exit 12)"
    test::should_return 12 Waiting::GetTaskStatus waiting
}
test::register_test Waiting::Test1
